package common

import (
	"fmt"
	"reflect"
	"strconv"
	"strings"
)

// 切片转换为csv
func SliceToCsv(data []map[string]any) string {
	var csvStrings []string
	for _, item := range data {
		var str []string
		for _, value := range item {
			str = append(str, fmt.Sprintf("%v", value))
		}
		csvStrings = append(csvStrings, strings.Join(str, ","))
	}
	return strings.Join(csvStrings, "\n")
}

// map转换为csv
func MapToCsv(data map[string]any) string {
	var csvStrings []string
	for key, value := range data {
		csvStrings = append(csvStrings, key+","+fmt.Sprintf("%v", value))
	}
	return strings.Join(csvStrings, "\n")
}

// 获取csv的标题
func GetCsvTitle(data interface{}) (string, error) {
	val := reflect.ValueOf(data)
	if val.Kind() != reflect.Struct {
		return "", fmt.Errorf("不是结构体类型, 而是 %v", val.Kind())
	}
	var csvStrings []string
	for i := 0; i < val.NumField(); i++ {
		field := val.Type().Field(i)
		//判断是否有tag ,`csv:"-"`  ,如果有则不添加
		if field.Tag.Get("csv") == "-" {
			continue
		}
		//获取tag  ,`csv:"name"`
		tag := field.Tag.Get("csv")
		if tag != "" {
			csvStrings = append(csvStrings, tag)
			continue
		}
		//如果没有tag,则使用字段名
		csvStrings = append(csvStrings, field.Name)
	}
	return strings.Join(csvStrings, ","), nil
}

// 将结构体转换为csv, 仅支持string和int ,float类型
func StructToCsv(data interface{}) (string, error) {
	val := reflect.ValueOf(data)
	if val.Kind() != reflect.Struct {
		return "", fmt.Errorf("不是结构体类型, 而是 %v", val.Kind())
	}

	var csvStrings []string
	for i := 0; i < val.NumField(); i++ {
		field := val.Field(i)
		switch field.Kind() {
		case reflect.String:
			csvStrings = append(csvStrings, field.String())
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			csvStrings = append(csvStrings, strconv.FormatInt(field.Int(), 10))
		case reflect.Float32, reflect.Float64:
			csvStrings = append(csvStrings, strconv.FormatFloat(field.Float(), 'f', -1, 64))
		case reflect.Bool:
			csvStrings = append(csvStrings, strconv.FormatBool(field.Bool()))
		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: //符号整型
			csvStrings = append(csvStrings, strconv.FormatUint(field.Uint(), 10))
		case reflect.Interface:
			csvStrings = append(csvStrings, fmt.Sprintf("%v", field.Interface()))
		default:
			return "", fmt.Errorf("unsupported field type: %v", field.Type())
		}
	}

	return strings.Join(csvStrings, ","), nil
}

// 多个结构体转换为csv
func StructsToCsv(data any) (string, error) {
	//判断是否是切片
	val := reflect.ValueOf(data)
	if val.Kind() != reflect.Slice {
		return "", fmt.Errorf("参数不是切片类型, 你的传入的类型是: %v", val.Kind())
	}
	//获取切片的长度
	valLen := val.Len()
	if valLen == 0 {
		return "", fmt.Errorf("没有数据")
	}
	var csvStrings []string
	for i := 0; i < valLen; i++ {
		if val.Index(i).Kind() != reflect.Struct {
			return "", fmt.Errorf("切片内的数据不是结构体类型, 你的类型是: %v", val.Index(i).Kind())
		}
		//拿到第一个元素
		csvStr, err := StructToCsv(val.Index(i).Interface())
		if err != nil {
			return "", err

		}
		csvStrings = append(csvStrings, csvStr)

	}
	return strings.Join(csvStrings, "\n"), nil
}

// 输出标准的csv格式字符串
func StructsToCsvWithHeader(data any) (string, error) {
	//判断是否是切片
	val := reflect.ValueOf(data)
	if val.Kind() != reflect.Slice {
		return "", fmt.Errorf("参数不是切片类型, 你的传入的类型是:%v", val.Kind())
	}
	//获取切片的长度
	valLen := val.Len()
	if valLen == 0 {
		return "", fmt.Errorf("没有数据")
	}
	header, err := GetCsvTitle(val.Index(0).Interface())
	if err != nil {
		return "", err
	}
	csvStr, err := StructsToCsv(data)
	if err != nil {
		return "", err
	}
	return header + "\n" + csvStr, nil
}
